package plugin

import (
	"context"
	"fmt"
	"gitee.com/tietang/terrace-go/v2/base"
	"github.com/antonmedv/expr"
	log "github.com/sirupsen/logrus"
	"reflect"
	"strings"
)

type Plugin interface {
	PluginCode() string
}
type Ordered interface {
	Order() int
}
type DefaultPlugin struct {
	Code string
}

func (b *DefaultPlugin) PluginCode() string {
	return b.Code
}

type PluginId interface {
	PluginCode() string
	Ability() string
}

func New(svc interface{}) *PluginDef {

	e := new(PluginDef)
	typ := reflect.TypeOf(svc)
	for i := 0; i < typ.NumMethod(); i++ {
		m := typ.Method(i)
		e.Ability = m.Name
		e.Func = func() {
		}
	}
	return e
}

type PluginDef struct {
	Plugin
	Service interface{}
	Func    interface{}
	Ability string
	Desc    string
	Order   int
}

func (d *PluginDef) String() string {
	return fmt.Sprintf("%s.%s: %v,%v", d.PluginCode(), d.Ability, d.Service, d.Func)
}

type PluginDefs []*PluginDef

func (p PluginDefs) Len() int {
	return len(p)
}
func (p PluginDefs) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
func (p PluginDefs) Less(i, j int) bool {
	return p[i].Order > p[j].Order
}

type DTO struct {
}

type RuleChecker interface {
	/**
	业务规则检查，是否可以执行该扩展
	*/
	Check(ctx context.Context, in interface{}) bool
}

var _ RuleChecker = new(ExprRuleChecker)

//规则表达式配置示列
//[rule]
//domain.order.create.ext.mt = Source==2
type ExprRuleChecker struct {
	PluginId PluginId
}

//rule expr: rule.[bizCode].[ability]
func (o *ExprRuleChecker) Check(ctx context.Context, in interface{}) bool {
	conf := base.Props()
	if o.PluginId == nil {
		log.Error("can't implements RuleChecker interface: ", reflect.TypeOf(o).String())
		return conf.GetBoolDefault("rule.default.action", true)
	}
	bizCode := strings.ReplaceAll(o.PluginId.PluginCode(), ":", ".")
	bizCode = strings.ReplaceAll(bizCode, "/", ".")
	ability := strings.ReplaceAll(o.PluginId.Ability(), ":", ".")
	ability = strings.ReplaceAll(ability, "/", ".")
	ruleKey := fmt.Sprintf("rule.%s.%s", bizCode, ability)
	ruleExpr, err := conf.Get(ruleKey)
	if ruleExpr == "" || err != nil {
		log.Error("can't found rule expr for key: ", ruleKey)
		return false
	}
	program, err := expr.Compile(ruleExpr, expr.Env(in))
	output, err := expr.Run(program, in)
	if err != nil {
		return false
	}
	if can, ok := output.(bool); ok {
		return can
	} else {
		log.Errorf("规则表达式 返回值不为bool值 for: %s = %s \n", ruleKey, ruleExpr)
		return false
	}

	return true
}

var _ RuleChecker = new(BaseRuleChecker)

type BaseRuleChecker struct {
	PluginId
	ExtExecutor PluginExecutor
}

func (o *BaseRuleChecker) Check(ctx context.Context, in interface{}) bool {
	return true
}
func (o *BaseRuleChecker) PluginCode() string {
	return "unknown"
}

type BasePlugin interface {
	PluginId
	OnValidate(ctx context.Context, in interface{}) error
	Pre(ctx context.Context, in interface{}) error
	Post(ctx context.Context, in interface{}, out interface{}) error
}

var _ BasePlugin = new(BaseRuleCheckerPlugin)

type BaseRuleCheckerPlugin struct {
	BaseRuleChecker
}

func (o *BaseRuleCheckerPlugin) PluginCode() string {
	return "unknown"
}
func (o *BaseRuleCheckerPlugin) OnValidate(ctx context.Context, in interface{}) error {
	return nil
}
func (o *BaseRuleCheckerPlugin) Pre(ctx context.Context, in interface{}) error {
	return nil
}
func (o *BaseRuleCheckerPlugin) Post(ctx context.Context, in interface{}, out interface{}) error {
	return nil
}
